package com.example.teemor.es_demo.logging;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import com.example.teemor.es_demo.entity.ServiceLog;
import com.example.teemor.es_demo.service.LogProducerService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.UUID;

/**
 * 自定义Kafka日志Appender
 * 用于拦截应用日志并发送到Kafka
 */
@Component
public class KafkaLogAppender extends AppenderBase<ILoggingEvent> implements ApplicationContextAware {
    
    private static ApplicationContext applicationContext;
    private LogProducerService logProducerService;
    private String serviceName = "es-demo";
    private String sourceIp;
    
    public KafkaLogAppender() {
        try {
            this.sourceIp = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            this.sourceIp = "unknown";
        }
    }
    
    @Override
    public void start() {
        super.start();
        if (applicationContext != null) {
            try {
                this.logProducerService = applicationContext.getBean(LogProducerService.class);
            } catch (Exception e) {
                // 忽略异常，可能是在Spring容器初始化之前
            }
        }
    }
    
    @Override
    protected void append(ILoggingEvent event) {
        // 避免循环日志
        if (event.getLoggerName().contains("kafka") || 
            event.getLoggerName().contains("LogProducerService")) {
            return;
        }
        
        if (logProducerService == null && applicationContext != null) {
            try {
                this.logProducerService = applicationContext.getBean(LogProducerService.class);
            } catch (Exception e) {
                return; // 如果无法获取服务，跳过此次日志
            }
        }
        
        if (logProducerService != null) {
            ServiceLog serviceLog = buildServiceLog(event);
            logProducerService.sendServiceLog(serviceLog);
        }
    }
    
    /**
     * 构建服务日志对象
     */
    private ServiceLog buildServiceLog(ILoggingEvent event) {
        // 生成TraceID（简单实现，实际项目中可以使用分布式追踪工具）
        String traceId = generateTraceId();
        
        // 提取类名和方法名
        String className = event.getLoggerName();
        String methodName = extractMethodName(event);
        
        // 处理异常信息
        String exceptionClass = null;
        String exceptionMessage = null;
        String stackTrace = null;
        if (event.getThrowableProxy() != null) {
            exceptionClass = event.getThrowableProxy().getClassName();
            exceptionMessage = event.getThrowableProxy().getMessage();
            // 构建堆栈信息
            StringBuilder sb = new StringBuilder();
            sb.append(event.getThrowableProxy().getClassName())
              .append(": ")
              .append(event.getThrowableProxy().getMessage());
            if (event.getThrowableProxy().getStackTraceElementProxyArray() != null) {
                for (int i = 0; i < Math.min(10, event.getThrowableProxy().getStackTraceElementProxyArray().length); i++) {
                    sb.append("\n\tat ").append(event.getThrowableProxy().getStackTraceElementProxyArray()[i]);
                }
            }
            stackTrace = sb.toString();
        }
        
        return ServiceLog.builder()
                .timestamp(LocalDateTime.ofInstant(
                    java.time.Instant.ofEpochMilli(event.getTimeStamp()),
                    ZoneId.systemDefault()))
                .serviceName(serviceName)
                .level(event.getLevel().toString())
                .threadId(event.getThreadName())
                .className(className)
                .methodName(methodName)
                .content(event.getFormattedMessage())
                .traceId(traceId)
                .sourceIp(sourceIp)
                .exceptionClass(exceptionClass)
                .exceptionMessage(exceptionMessage)
                .stackTrace(stackTrace)
                .build();
    }
    
    /**
     * 提取方法名（从堆栈信息中）
     */
    private String extractMethodName(ILoggingEvent event) {
        StackTraceElement[] callerData = event.getCallerData();
        if (callerData != null && callerData.length > 0) {
            return callerData[0].getMethodName();
        }
        return "unknown";
    }
    
    /**
     * 生成简单的TraceID
     */
    private String generateTraceId() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 16);
    }
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        KafkaLogAppender.applicationContext = applicationContext;
    }
    
    /**
     * 设置服务名称
     */
    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }
}